home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue28 / excel / EXCEL.ZIP / EXCELS.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  1997-08-07  |  9.2 KB  |  351 lines

  1. {*****************************************************}
  2. {       TExcel Component 3.1 for Delphi 1.0 .. 3.0    }
  3. {                                                     }
  4. {       Copyright (c) 1996, 1997 Tibor F. Liska       }
  5. {       Tel/Fax:    +36-1-165-2019                    }
  6. {       Office:     +36-1-209-5284                    }
  7. {       E-mail: liska@sztaki.hu                       }
  8. {*****************************************************}
  9. unit Excels;
  10.  
  11. interface
  12.  
  13. uses Forms, Classes, DdeMan, SysUtils;
  14.  
  15. type
  16.   TExcel = class(TComponent)
  17.   private
  18.       FMacro     : TFileName;
  19.       FMacroPath : TFileName;
  20.       FDDE       : TDdeClientConv;
  21.       FConnected : Boolean;
  22.       FExeName   : TFileName;
  23.       FDecimals  : Integer;
  24.       FSeparator : Char;
  25.       FWaitAfter : Integer;
  26.       FDone      : Integer;
  27.       FOnClose   : TNotifyEvent;
  28.       FOnOpen    : TNotifyEvent;
  29.     procedure SetExeName(const Value: TFileName);
  30.     function  GetSelection: string;
  31.     procedure SetConnect(const Value: Boolean);
  32.     function GetReady: Boolean;
  33.   protected
  34.     procedure OpenLink(Sender: TObject);
  35.     procedure ShutDown(Sender: TObject);
  36.     procedure LocateExcel;
  37.   public
  38.     constructor Create(AOwner: TComponent); override;
  39.     destructor Destroy; override;
  40.     procedure Connect;
  41.     procedure Disconnect;
  42.     procedure Wait;
  43.     function Request(const Item: string): string;
  44.     procedure Exec  (const Cmd : string);
  45.     procedure Run   (const Mn  : string);
  46.     procedure Filter(const Txt : string); virtual;
  47.     procedure Select(Row, Col: Integer);
  48.     procedure PutStr(Row, Col: Integer; const s: string);
  49.     procedure PutExt(Row, Col: Integer; e: Extended);
  50.     procedure PutInt(Row, Col: Integer; i: Longint);
  51.     procedure PutDay(Row, Col: Integer; d: TDateTime);
  52.     function GetCell(Row, Col: Integer): string;
  53.     procedure OpenMacroFile(const Fn: TFileName; Hide: Boolean);
  54.     procedure CloseMacroFile;
  55.     procedure StartTable(Create: Boolean);
  56.     procedure EndTable;
  57.     property DDE: TDdeCLientConv   read FDDE;
  58.     property Connected: Boolean    read FConnected write SetConnect;
  59.     property Ready    : Boolean    read GetReady;
  60.     property Selection: string     read GetSelection;
  61.   published
  62.     property ExeName  : TFileName  read FExeName   write SetExeName;
  63.     property Decimals : Integer    read FDecimals  write FDecimals;
  64.     property Separator: Char       read FSeparator write FSeparator;
  65.     property WaitAfter: Integer    read FWaitAfter write FWaitAfter;
  66.     property OnClose: TNotifyEvent read FOnClose   write FOnClose;
  67.     property OnOpen : TNotifyEvent read FOnOpen    write FOnOpen;
  68.   end;
  69.  
  70. procedure Register;
  71.  
  72. const                 { Message strings can be nationalized }
  73.      msgCannotRun     = 'Excel cannot be lunched';
  74.      msgNoConnect     = 'Excel not connected';
  75.      msgTableNotReady = 'Table is not ready';
  76.      msgNoReply       = '*** No Reply ***';
  77.      msgNotAccepted   ='" not accepted by Excel';
  78.      msgNoMacro       = 'Macro is not opened';
  79.      msgNoTable       = 'Table is not opened';
  80.  
  81. implementation
  82. uses WinTypes, WinProcs, ShellAPI;
  83.  
  84. procedure Register;
  85. begin
  86.   RegisterComponents('Liska', [TExcel]);
  87. end;
  88.  
  89. { TExcel }
  90.  
  91. constructor TExcel.Create(AOwner: TComponent);
  92. begin
  93.   inherited Create(AOwner);
  94.   if not (csDesigning in ComponentState) then
  95.   begin
  96.     FDDE := TDdeClientConv.Create(nil);
  97.     FDDE.ConnectMode := ddeManual;
  98.     FDDE.OnOpen  := OpenLink;
  99.     FDDE.OnClose := ShutDown;
  100.   end;
  101.   SetExeName('Excel');
  102.   FDecimals := 2;
  103.   FSeparator := DecimalSeparator;
  104.   FWaitAfter := 100;
  105.   FDone := 0;
  106. end;
  107.  
  108. destructor TExcel.Destroy;
  109. begin
  110.   if not (csDesigning in ComponentState) then
  111.     FDDE.Free;
  112.   inherited Destroy;
  113. end;
  114.  
  115. procedure TExcel.SetExeName(const Value: TFileName);
  116. begin
  117.   Disconnect;
  118.   FExeName := ChangeFileExt(Value, '');
  119.   if not (csDesigning in ComponentState) then
  120.     FDDE.ServiceApplication := FExeName;
  121. end;
  122.  
  123. function TExcel.GetSelection: string;
  124. begin
  125.   Result := Request('Selection');
  126. end;
  127.  
  128. procedure TExcel.SetConnect(const Value: Boolean);
  129. begin
  130.   if FConnected = Value then Exit;
  131.   if Value then Connect
  132.            else Disconnect;
  133. end;
  134.  
  135. function TExcel.GetReady: Boolean;
  136. begin
  137.   Result := 'Ready' = Request('Status');
  138. end;
  139.  
  140. procedure TExcel.OpenLink(Sender: TObject);
  141. begin
  142.   FConnected := True;
  143.   if Assigned(FOnOpen) then FOnOpen(Self);
  144. end;
  145.  
  146. procedure TExcel.ShutDown(Sender: TObject);
  147. begin
  148.   FConnected := False;
  149.   if Assigned(FOnClose) then FOnClose(Self);
  150. end;
  151.  
  152. procedure TExcel.LocateExcel;
  153.   const
  154.       BuffSize = 255;
  155.   var
  156.       Buff: array[0..BuffSize] of Char;
  157.       Fn  : string;
  158.       Len : Longint;
  159. begin
  160.   Len := BuffSize;
  161.   StrPCopy(Buff, '.XLS');
  162.   if (RegQueryValue(HKEY_CLASSES_ROOT, Buff, Buff, Len)
  163.     = ERROR_SUCCESS) and (StrScan(Buff,'E') <> nil) then
  164.   begin
  165.     StrCat(Buff, '\Shell\Open\Command');
  166.     Len := BuffSize;
  167.     if RegQueryValue(HKEY_CLASSES_ROOT, Buff, Buff, Len)
  168.       = ERROR_SUCCESS then
  169.     begin
  170.       Fn := StrPas(StrUpper(Buff));
  171.       Len := Pos('EXCEL.EXE', Fn);
  172.       Delete(Fn, Len + Length('EXCEL.EXE'), 255);
  173.       if Buff[0] = '"' then Delete(Fn, 1, 1);
  174.       if FileExists(Fn) then
  175.         ExeName := Fn;
  176.     end;
  177.   end;
  178. end;
  179.  
  180. procedure TExcel.Connect;
  181. begin
  182.   if FConnected then Exit;
  183.   FDDE.SetLink('Excel', 'System');
  184.   if FDDE.OpenLink then Exit;
  185.   LocateExcel;
  186.   if FDDE.OpenLink then Exit;            { Try again }
  187.   Application.ProcessMessages;
  188.   if FDDE.OpenLink then Exit;            { Once more }
  189.   raise Exception.Create(msgCannotRun);
  190. end;
  191.  
  192. procedure TExcel.Disconnect;
  193. begin
  194.   if FConnected then FDDE.CloseLink;
  195. end;
  196.  
  197. procedure TExcel.Wait;
  198. begin
  199.   Application.ProcessMessages;
  200.   FDone := 0;
  201.   while not Ready do
  202.     Application.ProcessMessages;      { Waiting for Excel }
  203. end;
  204.  
  205. function TExcel.Request(const Item: string): string;
  206.   var
  207.       Reply : PChar;
  208. begin
  209.   Application.ProcessMessages;
  210.   Reply := FDDE.RequestData(Item);
  211.   if Reply = nil then Result := msgNoReply
  212.                  else Result := StrPas(Reply);
  213.   StrDispose(Reply);
  214. end;
  215.  
  216. procedure TExcel.Exec(const Cmd: string);
  217.   var
  218.       a : array[0..255] of Char;
  219. begin
  220.   if not FConnected then
  221.     raise Exception.Create(msgNoConnect);
  222.   Inc(FDone);
  223.   if FDone < FWaitAfter then Application.ProcessMessages
  224.                         else Wait;
  225.   StrPCopy(a, Cmd);
  226.   if FDDE.ExecuteMacro(a, False) then Exit
  227.                                  else Wait;
  228.   if FDDE.ExecuteMacro(a, True ) then Exit;
  229.   raise Exception.Create('"' + Cmd + msgNotAccepted);
  230. end;
  231.  
  232. procedure TExcel.Run(const Mn: string);
  233. begin
  234.   if FMacro = '' then
  235.     raise Exception.Create(msgNoMacro);
  236.   Exec('[RUN("' + FMacro + '!' + Mn + '";FALSE)]');
  237. end;
  238.  
  239. procedure TExcel.Filter(const Txt: string);
  240.   var
  241.      i : Integer;
  242.      Send : string;
  243. begin
  244.   Send := Txt;
  245.   i := Pos('"', Send);
  246.   while i > 0 do
  247.   begin
  248.     Send[i] := '''';             { Filter out " }
  249.     i := Pos('"', Send);
  250.   end;
  251.   Exec('[FORMULA("'+Send+'")]');
  252. end;
  253.  
  254. procedure TExcel.Select(Row, Col: Integer);
  255. begin
  256.   Exec(Format('[SELECT("R%dC%d")]', [Row, Col]));
  257. end;
  258.  
  259. procedure TExcel.PutStr(Row, Col: Integer; const s: string);
  260. begin
  261.   Exec(Format('[FORMULA("%s","R%dC%d")]', [s, Row, Col]));
  262. end;
  263.  
  264. procedure TExcel.PutExt(Row, Col: Integer; e: Extended);
  265.   var
  266.      s : string;
  267.      i : Integer;
  268. begin
  269.   Str(e:0:Decimals, s);
  270.   if Separator <> '.' then
  271.   begin
  272.     i := Pos('.', s);
  273.     if i > 0 then s[i] := Separator;
  274.   end;
  275.   PutStr(Row, Col, s);
  276. end;
  277.  
  278. procedure TExcel.PutInt(Row, Col: Integer; i: Longint);
  279. begin
  280.   PutStr(Row, Col, IntToStr(i));
  281. end;
  282.  
  283. procedure TExcel.PutDay(Row, Col: Integer; d: TDateTime);
  284. begin
  285.   PutStr(Row, Col, DateToStr(d));
  286. end;
  287.  
  288. function TExcel.GetCell(Row, Col: Integer): string;
  289.   var
  290.       Topic : string;
  291.       i : Integer;
  292.       OldOpen,
  293.       OldClose : TNotifyEvent;
  294. begin
  295.   OldOpen  := FOnOpen;
  296.   OldClose := FOnClose;
  297.   FOnOpen  := nil;
  298.   FOnClose := nil;
  299. try
  300.   Topic := Request('Selection');
  301.   i := Pos('!', Topic);
  302.   if i = 0 then raise Exception.Create(msgNoTable);
  303.   FDDE.SetLink('Excel', Copy(Topic, 1, i-1));
  304.   if FDDE.OpenLink then Result := Request(Format('R%dC%d', [Row, Col]))
  305.                    else Result := msgNoReply;
  306. finally
  307.   FDDE.SetLink('Excel', 'System');
  308.   FDDE.OpenLink;
  309.   FOnOpen := OldOpen;
  310.   FOnClose:= OldClose;
  311. end; end;
  312.  
  313. procedure TExcel.OpenMacroFile(const Fn: TFileName; Hide: Boolean);
  314. begin
  315.   if FMacroPath = Fn then Exit;
  316.   CloseMacroFile;
  317.   Exec('[OPEN("' + Fn + '")]');
  318.   if Hide then Exec('[HIDE()]');
  319.   FMacroPath := Fn;
  320.   FMacro := ExtractFileName(Fn);
  321. end;
  322.  
  323. procedure TExcel.CloseMacroFile;
  324. begin
  325.   if FMacro <> '' then
  326.   try
  327.     Exec('[UNHIDE("' + FMacro + '")]');
  328.     Exec('[ACTIVATE("' + FMacro + '")]');
  329.     Exec('[CLOSE(FALSE)]');
  330.   finally
  331.     FMacro := '';
  332.     FMacroPath := '';
  333.   end;
  334. end;
  335.  
  336. procedure TExcel.StartTable(Create: Boolean);
  337. begin
  338.   Exec('[APP.MINIMIZE()]');
  339.   if Create then Exec('[NEW(1)]');
  340.   PutStr(1, 1, msgTableNotReady);
  341.   FDone := 0;
  342. end;
  343.  
  344. procedure TExcel.EndTable;
  345. begin
  346.   PutStr(1, 1, '');
  347.   Exec('[APP.RESTORE()]');
  348.   FDone := 0;
  349. end;
  350.  
  351. end.